﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine.UIElements;

namespace DA.AnimGraph.Editor {

    [NodeMenuItem(typeof(AGANode_AxisBlend1D), "Axis Blend 1D")]
    internal class NodeView_AxisBlend1D : NodeViewBase {

        public override string titleText => "Axis Blend 1D";
        protected override NodeViewInspectorSourceBase dataSource => inspectorData;
        private NodeViewInspector_AxisBlend1D inspectorData;
        internal override void Init(AGAHandle_Node handle, AnimGraphView graphView, AGEEnvironment ageContext) {
            inspectorData = new NodeViewInspector_AxisBlend1D();
            inspectorData.SetHandle(handle);
            base.Init(handle, graphView, ageContext);
        }
    }

    internal class NodeViewInspector_AxisBlend1D : NodeViewInspectorSourceBase {

        [InspectorField] public AGAFieldModel_FloatLink inputPosition;
        [InspectorField(tag: "inputPort", isList: true)]
        public List<AGAFieldModel_InputPort> inputPort;
        public List<AGAFieldModel_AxisBlend1DPort> portsPositions;

        protected override void LoadFromModel() {
            var model = handleKeeper.handle.data.modelProperty as AGANodeModel_AxisBlend1D;
            portsPositions = model.portsPositions;
            inputPosition = model.inputPosition;

            // inputPort
            var bNode = handleKeeper.handle.data as AGANode_BlendBase;
            int childrenCount = bNode.inputChildren.Count;
            inputPort = new List<AGAFieldModel_InputPort>(childrenCount);
            for (int i = 0; i < childrenCount; i++) {
                inputPort.Add(new AGAFieldModel_InputPort(bNode.inputNames[i], bNode.inputChildren[i]));
            }
        }
        protected override void SaveToModel() {
            // 全量覆盖保存输入端口
            var newInputs = inputPort.Select(m => (m.portUuid, m.name)).ToList();
            handleKeeper.handle.WriteAllInput(newInputs);

            handleKeeper.handle.SetDirty();
            var listView = inspectorWidgets["inputPort"] as ListViewAGE;
            listView.Rebuild();
        }

        protected override VisualElement CustomizeField(string name, InspectorFieldAttribute fieldAttribute, FieldInfo fieldInfo, AGEContext ageContext, Action inspectorChangeCallback) {
            if (fieldAttribute.tag == "inputPort") {
                return BuildPortListView(name, fieldAttribute, fieldInfo, ageContext, inspectorChangeCallback);
            }
            return base.CustomizeField(name, fieldAttribute, fieldInfo, ageContext, inspectorChangeCallback);
        }

        VisualElement BuildPortListView(string name, InspectorFieldAttribute fieldAttribute, FieldInfo fieldInfo, AGEContext ageContext, Action inspectorChangeCallback) {
            var listView = new ListViewAGE() {
                title = name,
                enableCountController = true,
                itemsSource = inputPort,
            };
            listView.makeItem = () => {
                var w = new FoldoutWrapper();
                w.upButtonClicked += (index) => {
                    (inputPort[index], inputPort[index - 1]) = (inputPort[index - 1], inputPort[index]);
                    inspectorChangeCallback?.Invoke();
                };
                w.downButtonClicked += (index) => {
                    (inputPort[index], inputPort[index + 1]) = (inputPort[index + 1], inputPort[index]);
                    inspectorChangeCallback?.Invoke();
                };
                w.deleteButtonClicked += (index) => {
                    var uuid2Delete = inputPort[index].portUuid;
                    inputPort.RemoveAt(index);
                    var index2Delete = portsPositions.FindIndex(p => p.portUuid == uuid2Delete);
                    if (index2Delete >= 0) {
                        portsPositions.RemoveAt(index2Delete);
                    } // 不进if是异常的
                    inspectorChangeCallback?.Invoke();
                };
                var l = new InspectorField_AB1DPort();
                return (l, w);
            };
            listView.bindItem = (element, wrapper, index) => {
                VisualElement nameInputField = null;
                if (element is InspectorField_AB1DPort field) {
                    var portUuid = inputPort[index].portUuid;
                    var portPosIndex = portsPositions.FindIndex(p => p.portUuid == portUuid);
                    field.Init(null, portsPositions[portPosIndex], ageContext, inspectorChangeCallback);
                    field.portField.Init(null, inputPort[index], ageContext, inspectorChangeCallback);
                    nameInputField = field.portField;
                }
                if (wrapper is FoldoutWrapper w) {
                    w.index = index;
                    w.text = $"[{index}]";
                    w.enableUp = index > 0;
                    w.enableDown = index < inputPort.Count - 1;
                    w.enableDelete = true;
                    w.SetToTitle(nameInputField);
                }
            };
            listView.addButtonClicked = () => {
                var newPort = new AGAFieldModel_InputPort("new port");
                inputPort.Add(newPort);
                var newPortPosition = new AGAFieldModel_AxisBlend1DPort(newPort.portUuid);
                newPortPosition.position.Add(0);
                portsPositions.Add(newPortPosition);
                inspectorChangeCallback?.Invoke();
            };
            return listView;
        }

        class InspectorField_AB1DPort : InspectorField<AGAFieldModel_AxisBlend1DPort> {

            public InspectorField_InputPort portField; // 这部分不再显示在foldout下，而是在标题上，这里只是持有对象而不添加到显示
            private ListViewAGE positionList;
            public InspectorField_AB1DPort() {
                portField = new() {
                    name = "name-field",
                    style = { flexGrow = 1, }
                };
            }

            protected override void BuildUI() {
                positionList = new ListViewAGE() {
                    title = "position",
                    enableCountController = true,
                };
                positionList.makeItem = () => {
                    var w = new InlineWrapper();
                    w.upButtonClicked += (index) => {
                        (source.position[index], source.position[index - 1]) = (source.position[index - 1], source.position[index]);
                        inspectorChangeCallback?.Invoke();
                    };
                    w.downButtonClicked += (index) => {
                        (source.position[index], source.position[index + 1]) = (source.position[index + 1], source.position[index]);
                        inspectorChangeCallback?.Invoke();
                    };
                    w.deleteButtonClicked += (index) => {
                        source.position.RemoveAt(index);
                        inspectorChangeCallback?.Invoke();
                    };
                    var l = new FloatField();
                    l.RegisterCallback<FocusOutEvent>(evt => OnPositionChanged());
                    return (l, w);
                };
                positionList.bindItem = (element, wrapper, index) => {
                    if (element is FloatField field) {
                        field.value = source.position[index];
                        field.label = $"[{index}]";
                    }
                    if (wrapper is InlineWrapper w) {
                        w.index = index;
                        w.enableUp = index > 0;
                        w.enableDown = index < source.position.Count - 1;
                        w.enableDelete = source.position.Count > 1;
                    }
                };
                positionList.addButtonClicked = () => {
                    source.position.Add(0);
                    positionList.Rebuild();
                    OnPositionChanged();
                };

            }

            protected override void DrawUI() {
                positionList.itemsSource = source.position;
                positionList.Rebuild();
                Add(positionList);

            }

            void OnPositionChanged() {
                // 不管哪一个修改，直接全量保存
                for (int i = 0; i < positionList.itemsUI.Count; i++) {
                    var value = ((FloatField)positionList.itemsUI[i]).value;
                    source.position[i] = value;
                }

                inspectorChangeCallback?.Invoke();
            }

        }

    }

}
